home *** CD-ROM | disk | FTP | other *** search
- // NewsAccess.m
-
- // A HyperAccess object provides access to hyperinformation, using particular
- // protocols and data format transformations. This one provides access to
- // the Internet/Usenet News system using NNTP/TCP().
-
- // History:
- // 26 Sep 90 Written TBL
-
- #define NEWS_PORT 119 /* See rfc977 */
- #define APPEND /* Use append methods */
- #define MAX_CHUNK 40 /* Largest number of articles in one window */
- #define CHUNK_SIZE 20 /* Optimum number of articles for quick display */
-
- #import "NewsAccess.h"
- #import <defaults/defaults.h>
- #import "Anchor.h"
- #import "HTParse.h"
- #import "HTStyle.h"
- #import <ctype.h>
-
- extern HTStyleSheet * styleSheet;
-
- #define NEXT_CHAR next_char()
- #define LINE_LENGTH 512 /* Maximum length of line of ARTICLE etc */
- #define GROUP_NAME_LENGTH 256 /* Maximum length of group name */
- /* Module parameters:
- ** -----------------
- **
- ** These may be undefined and redefined by syspec.h
- */
-
- #define NETCLOSE close /* Routine to close a TCP-IP socket */
- #define NETREAD read /* Routine to read from a TCP-IP socket */
- #define NETWRITE write /* Routine to write to a TCP-IP socket */
-
- #ifdef NeXT
- #import <libc.h> /* NeXT has all this packaged up */
- #define ntohs(x) (x)
- #define htons(x) (x)
- #else
- #include <string.h> /* For bzero etc */
- #include <stdio.h>
-
- /* TCP-specific types
- */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <errno.h> /* independent */
- #include <sys/time.h> /* independent */
- extern char *malloc();
- extern void free();
- extern char *strncpy();
- #endif
-
- #include <netinet/in.h>
- #include <arpa/inet.h> /* Must be after netinet/in.h */
- #include <netdb.h>
- #import <streams/streams.h>
- #import "HTUtils.h" /* Coding convention macros */
-
- @implementation NewsAccess
-
- // Module-wide variables
-
- static const char * NewsHost;
- static struct sockaddr_in soc_address; /* Binary network address */
- static int s; /* Socket for conn. to NewsHost */
- static char response_text[LINE_LENGTH+1]; /* Last response from NewsHost */
- static HyperText * HT; /* the new hypertext */
- static int diagnostic; /* level: 0=none 1=rtf 2=source */
-
- static HTStyle *addressStyle; /* For heading, from address etc */
- static HTStyle *textStyle; /* Text style */
-
- #define INPUT_BUFFER_SIZE 4096
- static char input_buffer[INPUT_BUFFER_SIZE]; /* Input buffer */
- static char * input_read_pointer;
- static char * input_write_pointer;
-
-
- /* Procedure: Read a character from the input stream
- ** -------------------------------------------------
- */
- PRIVATE char next_char(void)
- {
- int status;
- if (input_read_pointer >= input_write_pointer) {
- status = read(s, input_buffer, INPUT_BUFFER_SIZE); /* Get some more data */
- if (status <= 0) return (char)-1;
- input_write_pointer = input_buffer + status;
- input_read_pointer = input_buffer;
- }
- return *input_read_pointer++;
- }
-
-
- // Initialisaion for this class
- // ----------------------------
- //
- // We pick up the NewsHost name from, in order:
- //
- // 1. WorldWideWeb
- // 2. Global
- // 3. News
- // 4. Defualt to cernvax.cern.ch (!!!)
-
- + initialize
- {
- const struct hostent *phost; /* Pointer to host - See netdb.h */
- struct sockaddr_in* sin = &soc_address;
-
- /* Set up defaults:
- */
- sin->sin_family = AF_INET; /* Family = internet, host order */
- sin->sin_port = NEWS_PORT; /* Default: new port, */
-
- /* Get name of Host
- */
- if ((NewsHost = NXGetDefaultValue("WorldWideWeb","NewsHost"))==0)
- if ((NewsHost = NXGetDefaultValue("News","NewsHost")) == 0)
- NewsHost = "cernvax.cern.ch";
-
- if (*NewsHost>='0' && *NewsHost<='9') { /* Numeric node address: */
- sin->sin_addr.s_addr = inet_addr((char *)NewsHost); /* See arpa/inet.h */
-
- } else { /* Alphanumeric node name: */
- phost=gethostbyname((char*)NewsHost); /* See netdb.h */
- if (!phost) {
- NXRunAlertPanel(NULL, "Can't find internet node name `%s'.",
- NULL,NULL,NULL,
- NewsHost);
- CTRACE(tfp,
- "NewsAccess: Can't find internet node name `%s'.\n",NewsHost);
- return nil; /* Fail */
- }
- memcpy(&sin->sin_addr, phost->h_addr, phost->h_length);
- }
-
- if (TRACE) printf(
- "NewsAccess: Parsed address as port %4x, inet %d.%d.%d.%d\n",
- (unsigned int)ntohs(sin->sin_port),
- (int)*((unsigned char *)(&sin->sin_addr)+0),
- (int)*((unsigned char *)(&sin->sin_addr)+1),
- (int)*((unsigned char *)(&sin->sin_addr)+2),
- (int)*((unsigned char *)(&sin->sin_addr)+3));
-
- s=-1; /* Disconnected */
-
- return self;
- }
-
-
- // Return the name of the access
- // -----------------------------
-
- - (const char *)name
- {
- return "news";
- }
-
-
- // Get Styles from stylesheet
- //
- static void get_styles()
- {
- if (!addressStyle) addressStyle = HTStyleNamed(styleSheet, "Address");
- if (!textStyle) textStyle = HTStyleNamed(styleSheet, "Example");
- }
-
-
- /* Send NNTP Command line to remote host & Check Response
- ** ------------------------------------------------------
- **
- ** On entry,
- ** command points to the command to be sent, including CRLF, or is null
- ** pointer if no command to be sent.
- ** On exit,
- ** Negative status indicates transmission error, socket closed.
- ** Positive status is an NNTP status.
- */
-
-
- static int response(const char * command)
- {
- int result;
- char * p = response_text;
- if (command) {
- int status = write(s, command, strlen(command));
- if (status<0){
- if (TRACE) printf(
- "NewsAccess: Unable to send comand. Disconnecting.\n");
- close(s);
- s = -1;
- return status;
- } /* if bad status */
- if (TRACE) printf("NNTP command sent: %s", command);
- } /* if command to be sent */
-
- for(;;) {
- if (((*p++=NEXT_CHAR) == '\n') || (p == &response_text[LINE_LENGTH])) {
- *p++=0; /* Terminate the string */
- if (TRACE) printf("NNTP Response: %s\n", response_text);
- sscanf(response_text, "%i", &result);
- return result;
- } /* if end of line */
-
- if (*(p-1) < 0) return -1; /* End of file on response */
-
- } /* Loop over characters */
- }
-
-
- // Case insensitive string comparisons
- // -----------------------------------
- //
- // On entry,
- // template must be already un upper case.
- // unknown may be in upper or lower or mixed case to match.
- //
- static BOOL match(const char * unknown, const char * template)
- {
- const char * u = unknown;
- const char * t = template;
- for (;*u && *t && (toupper(*u)==*t); u++, t++) /* Find mismatch or end */ ;
- return (BOOL)(*t==0); /* OK if end of template */
- }
-
- // Find Author's name in mail address
- // ----------------------------------
- //
- // On exit,
- // THE EMAIL ADDRESS IS CORRUPTED
- //
- // For example, returns "Tim Berners-Lee" if given any of
- // " Tim Berners-Lee <tim@online.cern.ch> "
- // or " tim@online.cern.ch ( Tim Berners-Lee ) "
- //
- static char * author_name(char * email)
- {
- char *s, *e;
-
- if ((s=index(email,'(')) && (e=index(email, ')')))
- if (e>s) {
- *e=0; /* Chop off everything after the ')' */
- return HTStrip(s+1); /* Remove leading and trailing spaces */
- }
-
- if ((s=index(email,'<')) && (e=index(email, '>')))
- if (e>s) {
- strcpy(s, e+1); /* Remove <...> */
- return HTStrip(email); /* Remove leading and trailing spaces */
- }
-
- return HTStrip(email); /* Default to the whole thing */
-
-
- }
-
-
- /* Paste in an Anchor
- ** ------------------
- **
- **
- ** On entry,
- ** HT has a selection of zero length at the end.
- ** text points to the text to be put into the file, 0 terminated.
- ** addr points to the hypertext refernce address,
- ** terminated by white space, comma, NULL or '>'
- */
- static void write_anchor(const char * text, const char * addr)
- {
- char href[LINE_LENGTH+1];
-
- {
- const char * p;
- strcpy(href,"news:");
- for(p=addr; *p && (*p!='>') && !WHITE(*p) && (*p!=','); p++);
- strncat(href, addr, p-addr); /* Make complete hypertext reference */
- }
-
- [HT appendBeginAnchor:"" to:href];
- [HT appendText:text];
- [HT appendEndAnchor];
- }
-
- /* Write list of anchors
- ** ---------------------
- **
- ** We take a pointer to a list of objects, and write out each,
- ** generating an anchor for each.
- **
- ** On entry,
- ** HT has a selection of zero length at the end.
- ** text points to a comma or space separated list of addresses.
- ** On exit,
- ** *text is NOT any more chopped up into substrings.
- */
- static void write_anchors(char * text)
- {
- char * start = text;
- char * end;
- char c;
- for (;;) {
- for(;*start && (WHITE(*start)); start++); /* Find start */
- if (!*start) return; /* (Done) */
- for(end=start; *end && (*end!=' ') && (*end!=','); end++); /* Find end */
- if (*end) end++; /* Include comma or space but not NULL */
- c = *end;
- *end = 0;
- write_anchor(start, start);
- *end = c;
- start = end; /* Point to next one */
- }
- }
-
- /* Read in an Article
- ** ------------------
- */
- //
- // Note the termination condition of a single dot on a line by itself.
- // RFC 977 specifies that the line "folding" of RFC850 is not used, so we
- // do not handle it here.
-
- static void read_article()
- {
-
- char line[LINE_LENGTH+1];
- char *references=NULL; /* Hrefs for other articles */
- char *newsgroups=NULL; /* Newsgroups list */
- char *p = line;
- BOOL done = NO;
-
- /* Read in the HEADer of the article:
- **
- ** The header fields are either ignored, or formatted and put into the
- ** Text.
- */
- if (diagnostic!=2)
- #ifdef APPEND
- [HT appendStyle:addressStyle];
- #else
- [HT applyStyle:addressStyle];
- #endif
- while(!done){
- if (((*p++=NEXT_CHAR) == '\n') || (p == &line[LINE_LENGTH])) {
- *--p=0; /* Terminate the string */
- if (TRACE) printf("H %s\n", line);
- if (line[0]=='.') {
- if (line[1]<' ') { /* End of article? */
- done = YES;
- break;
- }
-
- } else if (line[0]<' ') {
- break; /* End of Header? */
- } else if (match(line, "SUBJECT:")) {
- [HT setTitle:line+8];
- } else if (match(line, "DATE:")
- || match(line, "FROM:")
- || match(line, "ORGANIZATION:")) {
- strcat(line, "\n");
- #ifdef APPEND
- [HT appendText:index(line,':')+1];
- #else
- [HT replaceSel:index(line,':')+1 style:addressStyle];
- #endif
- } else if (match(line, "NEWSGROUPS:")) {
- StrAllocCopy(newsgroups, HTStrip(index(line,':')+1));
-
- } else if (match(line, "REFERENCES:")) {
- StrAllocCopy(references, HTStrip(index(line,':')+1));
-
- } /* end if match */
- p = line; /* Restart at beginning */
- } /* if end of line */
- } /* Loop over characters */
-
- #ifdef APPEND
- [HT appendText:"\n"];
- [HT appendStyle:textStyle];
- #else
- [HT replaceSel:"\n" style:addressStyle];
- #endif
-
- if (newsgroups) {
- [HT appendText: "\nNewsgroups: "];
- write_anchors(newsgroups);
- free(newsgroups);
- }
-
- if (references) {
- [HT appendText: "\nReferences: "];
- write_anchors(references);
- free(references);
- }
-
- [HT appendText: "\n\n\n"];
-
- // Read in the BODY of the Article:
- //
- p = line;
- while(!done){
- if (((*p++=NEXT_CHAR) == '\n') || (p == &line[LINE_LENGTH])) {
- *p++=0; /* Terminate the string */
- if (TRACE) printf("B %s", line);
- if (line[0]=='.') {
- if (line[1]<' ') { /* End of article? */
- done = YES;
- break;
- } else { /* Line starts with dot */
- [HT appendText: &line[1]]; /* Ignore first dot */
- }
- } else {
-
- /* Normal lines are scanned for buried references to other articles.
- ** Unfortunately, it will pick up mail addresses as well!
- */
- char *l = line;
- char * p;
- while (p=index(l, '<')) {
- char *q=index(l,'>');
- if (q>p && index(p,'@')) {
- char c = q[1];
- q[1] = 0; /* chop up */
- *p = 0;
- [HT appendText:l];
- *p = '<'; /* again */
- *q = 0;
- [HT appendBeginAnchor:"" to:p+1];
- *q = '>'; /* again */
- [HT appendText:p];
- [HT appendEndAnchor];
- q[1] = c; /* again */
- l=q+1;
- } else break; /* line has unmatched <> */
- }
- [HT appendText: l]; /* Last bit of the line */
- } /* if not dot */
- p = line; /* Restart at beginning */
- } /* if end of line */
- } /* Loop over characters */
- }
-
-
- /* Read in a List of Newsgroups
- ** ----------------------------
- */
- //
- // Note the termination condition of a single dot on a line by itself.
- // RFC 977 specifies that the line "folding" of RFC850 is not used, so we
- // do not handle it here.
-
- static void read_list()
- {
-
- char line[LINE_LENGTH+1];
- char *p;
- BOOL done = NO;
-
- /* Read in the HEADer of the article:
- **
- ** The header fields are either ignored, or formatted and put into the
- ** Text.
- */
- #ifdef APPEND
- [HT appendText: "\nNewsgroups:\n\n"]; /* Should be haeding style */
- #else
- [HT replaceSel:"\nNewsgroups:\n\n" style:textStyle]; /* Should be heading */
- #endif
- p = line;
- while(!done){
- if (((*p++=NEXT_CHAR) == '\n') || (p == &line[LINE_LENGTH])) {
- *p++=0; /* Terminate the string */
- if (TRACE) printf("B %s", line);
- if (line[0]=='.') {
- if (line[1]<' ') { /* End of article? */
- done = YES;
- break;
- } else { /* Line starts with dot */
- #ifdef APPEND
- [HT appendText: &line[1]];
- #else
- [HT replaceSel:&line[1] style:textStyle]; /* Ignore first dot */
- #endif
- }
- } else {
-
- /* Normal lines are scanned for references to newsgroups.
- */
- char group[LINE_LENGTH];
- int first, last;
- char postable;
- if (sscanf(line, "%s %i %i %c", group, &first, &last, &postable)==4)
- write_anchor(line, group);
- else
- #ifdef APPEND
- [HT appendText:line];
- #else
- [HT replaceSel:line style:textStyle];
- #endif
- } /* if not dot */
- p = line; /* Restart at beginning */
- } /* if end of line */
- } /* Loop over characters */
- }
-
-
- /* Read in a Newsgroup
- ** -------------------
- ** Unfortunately, we have to ask for each article one by one if we want more
- ** than one field.
- **
- */
- void read_group(const char * groupName, int first_required, int last_required)
- {
- char line[LINE_LENGTH+1];
- char author[LINE_LENGTH+1];
- char subject[LINE_LENGTH+1];
- char *p;
- BOOL done;
-
- char buffer[LINE_LENGTH];
- char *reference=0; /* Href for article */
- int art; /* Article number WITHIN GROUP */
- int status, count, first, last; /* Response fields */
- /* count is only an upper limit */
-
- sscanf(response_text, " %i %i %i %i", &status, &count, &first, &last);
- if(TRACE) printf("Newsgroup status=%i, count=%i, (%i-%i) required:(%i-%i)\n",
- status, count, first, last, first_required, last_required);
- if (last==0) {
- [HT appendText: "\nNo articles in this group.\n"];
- return;
- }
-
- #define FAST_THRESHOLD 100 /* Above this, read IDs fast */
- #define CHOP_THRESHOLD 50 /* Above this, chop off the rest */
-
- if (first_required<first) first_required = first; /* clip */
- if ((last_required==0) || (last_required > last)) last_required = last;
-
- if (last_required<=first_required) {
- [HT appendText: "\nNo articles in this range.\n"];
- return;
- }
-
- if (last_required-first_required+1 > MAX_CHUNK) { /* Trim this block */
- first_required = last_required-CHUNK_SIZE+1;
- }
- if (TRACE) printf (" Chunk will be (%i-%i)\n", first_required, last_required);
-
- /* Link to earlier articles
- */
- if (first_required>first) {
- int before; /* Start of one before */
- if (first_required-MAX_CHUNK <= first) before = first;
- else before = first_required-CHUNK_SIZE;
- sprintf(buffer, "%s/%i-%i", groupName, before, first_required-1);
- if (TRACE) printf(" Block before is %s\n", buffer);
- [HT appendBeginAnchor:"" to:buffer];
- [HT appendText: " (Earlier articles...)\n\n"];
- [HT appendEndAnchor];
- }
-
- done = NO;
-
- /*#define USE_XHDR*/
- #ifdef USE_XHDR
- if (count>FAST_THRESHOLD) {
- sprintf(buffer,
- "\nThere are about %i articles currently available in %s, IDs as follows:\n\n",
- count, groupName);
- [HT appendText:buffer];
- anchor_start = [HT textLength];
- sprintf(buffer, "XHDR Message-ID %i-%i\n", first, last);
- status = response(buffer);
- if (status==221) {
-
- p = line;
- while(!done){
- if (((*p++=NEXT_CHAR) == '\n') || (p == &line[LINE_LENGTH])) {
- *p++=0; /* Terminate the string */
- if (TRACE) printf("X %s", line);
- if (line[0]=='.') {
- if (line[1]<' ') { /* End of article? */
- done = YES;
- break;
- } else { /* Line starts with dot */
- /* Ignore strange line */
- }
- } else {
-
- /* Normal lines are scanned for references to articles.
- */
- char * space = strchr(line, ' ');
- if (space++)
- write_anchor(space, space);
- } /* if not dot */
- p = line; /* Restart at beginning */
- } /* if end of line */
- } /* Loop over characters */
-
- /* leaving loop with "done" set */
- } /* Good status */
- };
- #endif
-
- /* Read newsgroup using individual fields:
- */
- if (!done) {
- if (first==first_required && last==last_required)
- [HT appendText:"\nAll available articles:\n\n"];
- else [HT appendText: "\nArticles:\n\n"];
- for(art=first_required; art<=last_required; art++) {
-
- /*#define OVERLAP*/
- #ifdef OVERLAP
- /* With this code we try to keep the server running flat out by queuing just
- ** one extra command ahead of time. We assume (1) that the server won't abort if
- ** it get input during output, and (2) that TCP buffering is enough for the
- ** two commands. Both these assumptions seem very reasonable. However, we HAVE had
- ** a hangup with a loaded server.
- */
- if (art==first_required) {
- if (art==last_required) {
- sprintf(buffer, "HEAD %i\n", art); /* Only one */
- status = response(buffer);
- } else { /* First of many */
- sprintf(buffer, "HEAD %i\nHEAD %i\n", art, art+1);
- status = response(buffer);
- }
- } else if (art==last_required) { /* Last of many */
- status = response(NULL);
- } else { /* Middle of many */
- sprintf(buffer, "HEAD %i\n", art+1);
- status = response(buffer);
- }
- #else
- sprintf(buffer, "HEAD %i\n", art);
- status = response(buffer);
- #endif
- if (status == 221) { /* Head follows - parse it:*/
-
- p = line; /* Write pointer */
- done = NO;
- while(!done){
- if ( ((*p++=NEXT_CHAR) == '\n')
- || (p == &line[LINE_LENGTH]) ) {
-
- *--p=0; /* Terminate & chop LF*/
- p = line; /* Restart at beginning */
- if (TRACE) printf("G %s\n", line);
- switch(line[0]) {
-
- case '.':
- done = (line[1]<' '); /* End of article? */
- break;
-
- case 'S':
- case 's':
- if (match(line, "SUBJECT:"))
- strcpy(subject, line+8); /* Save author */
- break;
-
- case 'M':
- case 'm':
- if (match(line, "MESSAGE-ID:")) {
- char * addr = HTStrip(line+11) +1; /* Chop < */
- addr[strlen(addr)-1]=0; /* Chop > */
- StrAllocCopy(reference, addr);
- }
- break;
-
- case 'f':
- case 'F':
- if (match(line, "FROM:"))
- strcpy(author, author_name(index(line,':')+1));
- break;
-
- } /* end switch on first character */
- } /* if end of line */
- } /* Loop over characters */
-
- sprintf(buffer, "\"%s\" - %s\n", subject, author);
- if (reference) {
- write_anchor(buffer, reference);
- free(reference);
- reference=0;
- } else {
- [HT appendText:buffer];
- }
-
-
- /* Change the title bar to indicate progress!
- */
- if (art%10 == 0) {
- sprintf(buffer, "Reading newsgroup %s, Article %i (of %i-%i) ...",
- groupName, art, first, last);
- [HT setTitle:buffer];
- }
-
- } /* If good response */
- } /* Loop over article */
- } /* If read headers */
-
- /* Link to later articles
- */
- if (last_required<last) {
- int after; /* End of article after */
- after = last_required+CHUNK_SIZE;
- if (after==last) sprintf(buffer, "news:%s", groupName); /* original group */
- else sprintf(buffer, "news:%s/%i-%i", groupName, last_required+1, after);
- if (TRACE) printf(" Block after is %s\n", buffer);
- [HT appendBeginAnchor:"" to:buffer];
- [HT appendText: "\n(Later articles...)\n"];
- [HT appendEndAnchor];
- }
-
- /* Set window title
- */
- sprintf(buffer, "Newsgroup %s, Articles %i-%i",
- groupName, first_required, last_required);
- [HT setTitle:buffer];
-
- }
-
-
- // Open by name -accessName:anchor:diagnostic:
- // ------------
-
- - accessName:(const char *)arg
- anchor:(Anchor *)anAnchor
- diagnostic:(int)diag
- {
- char command[257]; /* The whole command */
- char groupName[GROUP_NAME_LENGTH]; /* Just the group name */
- int status; /* tcp return */
- int retries; /* A count of how hard we have tried */
- BOOL group_wanted; /* Flag: group was asked for, not article */
- BOOL list_wanted; /* Flag: group was asked for, not article */
- int first, last; /* First and last articles asked for */
-
- diagnostic = diag; /* set global flag */
-
- if (TRACE) printf("NewsAccess: Looking for %s\n", arg);
- get_styles();
- {
- char * p1;
-
- /* We will ask for the document, omitting the host name & anchor.
- **
- ** Syntax of address is
- ** xxx@yyy Article
- ** <xxx@yyy> Same article
- ** xxxxx News group (no "@")
- */
- group_wanted = (index(arg, '@')==0) && (index(arg, '*')==0);
- list_wanted = (index(arg, '@')==0) && (index(arg, '*')!=0);
-
- p1 = HTParse(arg, "", PARSE_PATH|PARSE_PUNCTUATION);
- if (list_wanted) {
- strcpy(command, "LIST ");
- } else if (group_wanted) {
- char * slash = strchr(p1, '/');
- strcpy(command, "GROUP ");
- first = 0;
- last = 0;
- if (slash) {
- *slash = 0;
- strcpy(groupName, p1);
- *slash = '/';
- (void) sscanf(slash+1, "%i-%i", &first, &last);
- } else {
- strcpy(groupName, p1);
- }
- strcat(command, groupName);
- } else {
- strcpy(command, "ARTICLE ");
- if (index(p1, '<')==0) strcat(command,"<");
- strcat(command, p1);
- if (index(p1, '>')==0) strcat(command,">");
- }
- free(p1);
-
- strcat(command, "\r\n"); /* CR LF, as in rfc 977 */
-
- } /* scope of p1 */
-
- if (!*arg) return nil; // Ignore if no name
-
-
- // Make a hypertext object with an anchor list.
-
- HT = [HyperText newAnchor:anAnchor Server:self];
-
- [HT setupWindow];
- [HT selectText:self]; /* Replace everything with what's to come */
-
- // Now, let's get a stream setup up from the NewsHost:
-
- for(retries=0;retries<2; retries++){
-
- if (s<0) {
- [[HT window]setTitle:"Connecting to NewsHost ..."]; /* Tell user */
- s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- status = connect(s, (struct sockaddr*)&soc_address, sizeof(soc_address));
- if (status<0){
- char message[256];
- close(s);
- s=-1;
- if (TRACE) printf("NewsAccess: Unable to connect to news host.\n");
- /* if (retries<=1) continue; WHY TRY AGAIN ? */
- NXRunAlertPanel(NULL,
- "Could not access newshost %s.",
- NULL,NULL,NULL,
- NewsHost);
- sprintf(message,
- "\nCould not access %s.\n\n (Check default WorldWideWeb NewsHost ?)\n",
- NewsHost);
- [HT setText:message];
- return HT;
- } else {
- if (TRACE) printf("NewsAccess: Connected to news host %s.\n",
- NewsHost);
- if ((response(NULL) / 100) !=2) {
- close(s);
- s=-1;
- NXRunAlertPanel("News access",
- "Could not retrieve information:\n %s.",
- NULL,NULL,NULL,
- response_text);
- [[HT window]setTitle: "News host response"];
- [HT setText:response_text];
- return HT;
- }
- }
- } /* If needed opening */
-
- [[HT window]setTitle:arg]; /* Tell user something's happening */
- status = response(command);
- if (status<0) break;
- if ((status/ 100) !=2) {
- NXRunAlertPanel("News access", response_text,
- NULL,NULL,NULL);
- [HT setText:response_text];
- close(s);
- s=-1;
- // return HT; -- no:the message might be "Timeout-disconnected" left over
- continue; // Try again
- }
-
- // Load a group, article, etc
- //
- [HT appendBegin];
-
- if (list_wanted) read_list();
- else if (group_wanted) read_group(groupName, first, last);
- else read_article();
-
- [HT appendEnd];
-
- [HT setEditable:NO]; /* This is read-only data */
- [HT adjustWindow];
- return HT;
-
- } /* Retry loop */
-
- [HT setText:"Sorry, could not load requested news.\n"];
-
- /* NXRunAlertPanel(NULL, "Sorry, could not load `%s'.",
- NULL,NULL,NULL, arg); No -- message earlier wil have covered it */
- return HT;
- }
-
- // Actions:
- // =======
-
-
- // This will load an anchor which has a name
- // -----------------------------------------
- //
- // On entry,
- // Anchor's address is valid.
- // On exit:
- // If there is no success, nil is returned.
- // Otherwise, the anchor is returned.
- //
-
- - loadAnchor: (Anchor *) a Diagnostic:(int)diagnostic
- {
- HyperText * HT;
-
- if (![a node]) {
- HT = [self accessName:[a address] anchor:a diagnostic:diagnostic];
- if (!HT) return nil;
- [[HT window] setDocEdited:NO];
- }
- return a;
- }
- @end
-